package com.ds.infrastructure.hyperspace.console.service.impl;

import com.alibaba.fastjson.JSONException;
import com.ds.infrastructure.hyperspace.console.config.shiro.ShiroToken;
import com.ds.infrastructure.hyperspace.console.config.sso.SSOConfig;
import com.ds.infrastructure.hyperspace.console.exceptions.HyperspaceException;
import com.ds.infrastructure.hyperspace.console.service.inf.ISSOService;
import com.ds.infrastructure.hyperspace.console.utils.FastJsonUtil;
import com.ds.infrastructure.hyperspace.console.utils.HttpUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.fluent.Request;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthenticatedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * SSO管理
 *
 * @author: yaozhendong
 * @create: 2019-11-18 16:00
 **/
@Slf4j
@Service
public class SSOService implements ISSOService {
    private static final String AUTH_HEADER_KEY = "Authorization";
    private static final String USER_INFO_4_STATUS_SUCCESS = "enable";
    private static final String ERROR_IO_EXCEPTION = "IOException:";
    private static final String ERROR_JSON_EXCEPTION = "JSONException:";
    private static final String ERROR_EXCEPTION = "Exception:";
    @Autowired
    SSOConfig ssoConfig;

    @Override
    public ShiroToken.User getCurrentUser() {
        if (ssoConfig.isEnable()) {
            ShiroToken.User user = (ShiroToken.User) SecurityUtils.getSubject().getPrincipal();
            if (user == null) {
                throw new HyperspaceException("user is null");
            }
            return user;
        }
        //关闭权限控制时返回：测试账号信息,方便测试
        return new ShiroToken().getTestUserForCloseShiro();
    }

    @Override
    public UserId validateTicket(String ticket) {
        String url = getSSOUrlPath(ssoConfig.getSsoPath().getValidatePath()) + "?service=" + ssoConfig.getService() + "&ticket=" + ticket;
        try {
            String response = HttpUtil.getRequest(url).execute().handleResponse((ResponseHandler<String>) httpResponse -> EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8));
            log.info(response);
            UserId userId = FastJsonUtil.deserialize(response, UserId.class);
            if (userId == null) {
                throw new HyperspaceException("SSO:验证Ticket失败，找到有效的session信息");
            }
            if (userId.getSid() == null) {
                throw new HyperspaceException("SSO:验证Ticket失败，Ticket:" + userId.getMsg());
            }
            return userId;
        } catch (IOException e) {
            log.error(ERROR_IO_EXCEPTION, e);
            throw new HyperspaceException("SSO:验证Ticket失败，IOException:" + e.getMessage());
        } catch (JSONException e) {
            log.error(ERROR_JSON_EXCEPTION, e);
            throw new HyperspaceException("SSO:验证Ticket失败，JSONException:" + e.getMessage());
        } catch (HyperspaceException e) {
            throw new HyperspaceException(e.getMessage());
        } catch (Exception e) {
            log.error(ERROR_EXCEPTION, e);
            throw new HyperspaceException("SSO:验证Ticket失败，Exception:" + e.getMessage());
        }
    }

    @Override
    public UserInfo getUserInfo(String sid) {
        if (StringUtils.isBlank(sid)) {
            throw new UnauthenticatedException("SSO:获取用户信息失败，Exception: sid is null");
        }
        String url = getSSOUrlPath(ssoConfig.getSsoPath().getUserInfoPath());
        try {
            String response = HttpUtil.getRequest(url)
                    .addHeader(new BasicHeader(AUTH_HEADER_KEY, sid))
                    .execute().handleResponse((ResponseHandler<String>) httpResponse -> EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8));
            log.info(response);
            UserInfo userInfo = FastJsonUtil.deserialize(response, UserInfo.class);
            if (userInfo == null || !USER_INFO_4_STATUS_SUCCESS.equals(userInfo.getStatus())) {
                throw new UnauthenticatedException("SSO:获取用户信息失败，没有找到有效的用户信息");
            }
            return userInfo;
        } catch (IOException e) {
            log.error(ERROR_IO_EXCEPTION, e);
            throw new UnauthenticatedException("SSO:获取用户信息失败，IOException:" + e.getMessage());
        } catch (JSONException e) {
            log.error(ERROR_JSON_EXCEPTION, e);
            throw new UnauthenticatedException("SSO:获取用户信息失败，JSONException:" + e.getMessage());
        } catch (UnauthenticatedException e) {
            throw new UnauthenticatedException(e.getMessage());
        } catch (Exception e) {
            log.error(ERROR_EXCEPTION, e);
            throw new UnauthenticatedException("SSO:获取用户信息失败，Exception:" + e.getMessage());
        }
    }

    private String getSSOUrlPath(String path) {
        return ssoConfig.getSsoUrl() + path;
    }

    @Data
    public static class UserId {
        private String sid;
        private String msg;
    }

    @Data
    public static class UserInfo {
        /**
         * 不一定存在
         */
        private String uid;
        /**
         * 一定存在
         */
        private String username;
        private String name;
        private String email;
        private String status;
        private boolean admin;
    }
}
